package com.miyu.system.service.book.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.miyu.common.pojo.book.BookPage;
import com.miyu.common.service.book.BookService;
import com.miyu.common.utils.commonUtils.Comutils;
import com.miyu.common.utils.redis.redisUtils.RedisCache;
import com.miyu.system.dao.book.BookMainDao;
import com.miyu.common.pojo.system.SysRule;
import com.miyu.system.service.book.SysBookService;
import com.miyu.system.service.rule.SysRuleService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;

/**
 * 系统书服务后端查询 + 搜索 + 数据实例化
 * @author miyu
 * @date 2022/11/08
 */
@Service
public class SysBookServiceImpl implements SysBookService {

    /** 系统规则服务 */
    @Resource
    private SysRuleService sysRuleService;
    @Resource
    private BookMainDao sysBookMainDao;

    @Resource
    private BookService bookService;

    @Resource
    private RedisCache redisCache;
    /**
     * 后端管理书籍查询
     * @param param 参数
     * @return {@link JSONArray}
     */
    @Override
    public JSONArray querySysBook(JSONObject param) {
        JSONArray rs = new JSONArray();
        String ruleId = param.getString("ruleId");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        //书籍 RuleType==1
        if(sysRule.getRuleType().equals("1")){
            //获取主表
            String bookMain = sysRule.getRuleId();
            StringBuffer sql = new StringBuffer();
            sql.append(" select * from book_main_").append(bookMain).append(" where 1=1 ");
            if(param.containsKey("bookName")&& StringUtils.isNotBlank(param.getString("bookName"))){
                sql.append(" and  book_name like '%").append(param.getString("bookName")).append("%'");
            }
            rs = sysBookMainDao.queryJSONArrayBySql(sql.toString());
        }
        return rs;
    }

    /**
     * 查询系统书细节
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject querySysBookDetail(JSONObject param) {
        JSONObject rs = new JSONObject();
        String ruleId = param.getString("ruleId");
        String bookId = param.getString("bookId");
        StringBuffer sql = new StringBuffer();
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        //书籍 RuleType==1
        if(sysRule.getRuleType().equals("1")) {
            //获取主表
            String bookMain = sysRule.getRuleId();
            sql.append(" select * from book_main_").append(bookMain).append(" where book_id = '").append(bookId).append("'");
            rs = sysBookMainDao.queryJSONObjectBySql(sql.toString());
        }
        return rs;
    }

    /**
     * 查询系统书章
     * @param param 参数
     * @return {@link JSONArray}
     */
    @Override
    public JSONArray querySysBookChapter(JSONObject param) {
        //根据ruleId 查询章节表所在表明
        String ruleId = param.getString("ruleId");
        String bookId = param.getString("bookId");
        /** 辅助主键*/
        String fpk = param.getString("fpk");
        StringBuffer sqlstr   = new StringBuffer();
        sqlstr.append(" select book_chapter_source from book_main_").append(ruleId).append( " where book_id ='").append(bookId).append("' ");
        JSONObject chapter = sysBookMainDao.queryJSONObjectBySql(sqlstr.toString());
        String chapterTable  = chapter.getString("bookChapterSource");
        JSONArray result = new JSONArray();
        String reader = chapterTable.replace("book_chapter_","book_reader_");
        /** 增加第一章节返回表*/
        StringBuffer sql = new StringBuffer();
        sql.append(" select *,'"+reader+"' bookReaderTable from book_chapter_").append(chapterTable).append(" where book_id = '").append(fpk).append("'");
        sql.append(" order by chapter_num asc");
        result = sysBookMainDao.queryJSONArrayBySql(sql.toString());
        return result;
    }

    /**
     * 查询系统书读者
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject querySysBookReader(JSONObject param) {
        //启动线程 执行缓存 保存数据 数据执行完毕后删除缓存
        String type="1";
        String bookReaderTable  = param.getString("bookReaderTable");
        String fpk  = param.getString("fpk");
        String bookId = param.getString("bookId");
        StringBuffer sql = new StringBuffer();
        sql.append(" select * from book_reader_").append(bookReaderTable).append(" where fpk ='").append(fpk).append("'");
        JSONObject chapter = sysBookMainDao.queryJSONObjectBySql(sql.toString());
        //重新封装处理月入文本字符
        JSONObject rs = new JSONObject();
        //表中不存在时 远程访问原资源
        if(chapter.isEmpty()){
            param.put("chapterUrl",param.getString("chapterSource"));
            JSONObject jsonObject = queryBookReader(param);
            JSONObject cpt = new JSONObject(jsonObject);
            cpt.put("chapterTable",bookReaderTable);
            cpt.put("chapterContext",jsonObject.getString("chapterContext"));
            cpt.put("fpk",fpk);
            executorService.submit(new BookSaveTaskJob(cpt,type));

            rs.put("chapterContext",jsonObject.getString("chapterContext"));
            rs.put("chapterNum",param.getString("chapterNum"));
        }else{
            rs.put("chapterContext",chapter.getString("chapterText"));
            rs.put("chapterNum",param.getString("chapterNum"));
        }
        String text = rs.getString("chapterContext");


        return rs;
    }

    /**
     * 收集图书阅读器缓存
     * @return {@link JSONObject}
     */
    public JSONObject collectBookReaderCache(){
        //取值缓存数据 此功能只使用与数据采集阅读章节 定时任务处理 不再手动处理
        //数据包含 规则Id 主键当前执行Id 每次执行范围 int类型  最终id
        //多线程启动单本数据缓存
        //1 根据id去除主数据
        //2. 根据主数据信息 多线程调用数据取值 进行缓存
        //3.充分利用缓存 后端默认进行定时任务进行更新定时任务重可进行 每次执行的数据量
        //4.自动定义缓存中进行到数据量 后再根据数据量 在进行取值 做到自动更新数据功能
        JSONObject data =  JSONObject.parseObject(redisCache.get("system:task:bookReader"));
        String ruleId = data.getString("ruleId");
        //开始
        int start = data.getIntValue("start");
        //执行范围
        int count = data.getIntValue("count");
        //当次最终end
        int end = data.getInteger("end"); ;
        int num;
        if(start+count>end ){
            num=end;
        }else{
            num=start+count;
        }


        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(4, new BasicThreadFactory.Builder().namingPattern("readerThead-%d").daemon(true).build());

        for (int i = start; i < num; i++) {
            StringBuffer sql = new StringBuffer();
            //根据主数据循环取值章节信息
            //多线程发送 取值 保存 此方法不在执行
            sql.append(" select *  from book_main_").append(ruleId).append("  where book_id = ").append(i);
            JSONObject main = sysBookMainDao.queryJSONObjectBySql(sql.toString());
            if(main!=null){
               //走多线程
                executorService.submit(new CacheBookTask(main,1));
            };
        }
        data.put("start", num);
        redisCache.set("system:task:bookReader",data);
        return null;
    }

    /**
     * 书籍采集功能（爬虫）
     * @param param 参数
     * @return {@link JSONObject}
     */
    //启动线程 执行缓存 保存数据 数据执行完毕后删除缓存
    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(4, new BasicThreadFactory.Builder()
            .namingPattern("saveBookThead-%d").daemon(true).build());
    @Override
    public JSONObject collectBook(JSONObject param) {
        String key = "book:collect:book";
        JSONObject saveJson = new JSONObject();
        saveJson.put("key", key);
        saveJson.put("type", "0");
        //1 整理url连接
        //2 获取书籍明细
        //3 获取章节
        //4 整合数据 缓存redis

        Integer start  = param.getInteger("start");
        Integer end = param.getInteger("end");
        String ruleId = param.getString("ruleId");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        for (int i = start; i <= end; i++) {
            String url = param.getString("url");
            url  =  StrUtil.format(url,i);

            System.out.println(url);

//        String url = param.getString("url");
        BookPage bookPage = new BookPage();
        bookPage.setRuleId(ruleId);
        bookPage.setRule(JSONObject.parseObject(sysRule.getRuleSet()));
        bookPage.setUrl(url);
        bookPage.setKey("book:collect:temp:"+Comutils.MD5(url));
        bookPage.setRemove(true);
        executorService.submit(new CollectBookJob(bookPage));
//        JSONObject bookDetail = bookService.queryBookDetail(bookPage);
//        if(bookDetail==null){
//            //没有明细url 跳出
//            continue;
//        }
//        bookPage.setUrl(bookDetail.getString("chapterUrl"));
//        bookPage.setKey("book:collect:temp:"+Comutils.MD5(bookDetail.getString("chapterUrl")));
//        JSONArray chapter = bookService.queryBookChapter(bookPage);
//        JSONObject book = new JSONObject();
//        book.put("main",bookDetail);
//        book.put("chapter",chapter);
//        redisCache.append(key,book);
 //       return book;
        }
       return null;
    }
    @Override
    public JSONObject collectBookSave() {
        String key = "book:collect:book";
        JSONObject saveJson = new JSONObject();
        saveJson.put("key", key);
        saveJson.put("type", "0");

        executorService.submit(new BookTaskJob(saveJson));
        return null;
    }

    /**
     * 保存缓存书任务
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject saveCacheBookTask(JSONObject param) {
        redisCache.set("system:task:bookReader",param);
        return null;
    }

    /**
     * 查询书（爬虫）
     * @param param 参数
     * @return {@link JSONArray}
     */
    @Override
    public JSONArray queryBook(JSONObject param) {
        String ruleId = param.getString("ruleId");
        String bookInfo = param.getString("bookInfo");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
        String url =  StrUtil.format(sysRule.getRootSearch(),bookInfo);
        BookPage bookPage = new BookPage();
        bookPage.setRuleId(ruleId);
        bookPage.setUrl(url);
        bookPage.setRule(rule);
        bookPage.setRemove(false);
        JSONArray rs = bookService.querySearchBook(bookPage);
        return rs;
    }

    /**
     * 查询书详情（爬虫）
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject queryBookDetail(JSONObject param) {
        String ruleId = param.getString("ruleId");
        String url = param.getString("bookUrl");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
        BookPage bookPage = new BookPage();
        bookPage.setRuleId(ruleId);
        bookPage.setUrl(url);
        bookPage.setRule(rule);
        return bookService.queryBookDetail(bookPage);
    }

    /**
     * 查询书章（爬虫）
     * @param param 参数
     * @return {@link JSONArray}
     */
    @Override
    public JSONArray queryBookChapter(JSONObject param) {
        String url = param.getString("chapterUrl");
        String ruleId = param.getString("ruleId");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
        BookPage bookPage = new BookPage();
        bookPage.setRuleId(ruleId);
        bookPage.setUrl(url);
        bookPage.setRule(rule);
        return  bookService.queryBookChapter(bookPage);
    }

    /**
     * 查询书读者（爬虫））
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject queryBookReader(JSONObject param) {
        String ruleId = param.getString("ruleId");
        String url = param.getString("chapterUrl");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
        BookPage bookPage = new BookPage();
        bookPage.setRuleId(ruleId);
        bookPage.setUrl(url);
        bookPage.setRule(rule);
        return bookService.queryBookReader(bookPage);
    }

    /**
     * 规则校验取值
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject checkBookRule(JSONObject param) {
        System.out.println("param"+param);
        String url = param.getString("url");
        String ruleStr = param.getString("ruleStr");
        BookPage bookPage = new BookPage();
        bookPage.setRuleStr(ruleStr);
        bookPage.setUrl(url);
        bookPage.setKey("book:checkBookRule");
        JSONObject jsonObject = bookService.checkBookRule(bookPage);
        return jsonObject;
    }



}
